﻿using System;
using System.Collections.Generic;
using System.Threading;

namespace Cluster
{
    public abstract partial class ClusterManager : IDisposable
    {
        private readonly ManualResetEvent connectionEvent = new ManualResetEvent(false);

        private readonly Guid uniqueId = Guid.NewGuid();

        public string ClusterName { get; private set; }
        public string ServerName { get; private set; }

        protected ClusterManager(string clusterName, string serverName)
        {
            ClusterName = clusterName;
            ServerName = serverName;
        }

        /// <summary>
        /// Starts the cluster manager.
        /// This would register us as a new node and start handling changes in the cluster.
        /// </summary>
        /// <param name="zkConnectionString">Zoo Keeper connection string</param>
        /// <param name="zkTimeout">timeout</param>
        public virtual void Start(string zkConnectionString, TimeSpan? zkTimeout = null)
        {
            ClusterView = new List<ClusterNode>();

            ReplicationView = new List<Replica>();

            ClusterViewChanged += ((o, e) => ScheduleReplication());
            ClusterViewChanged += ((o, e) => ScheduleBalancing());
            ClusterViewChanged += ((o, e) => ChoseLeader());

            StartZk(zkConnectionString, zkTimeout);

            SetupPaths();

            SetupReplication();

            DiscardOldReplicas();

            WatchReplicationPath();

            RegisterNode();

            RegisterServerReplication(ServerName);

            ScheduleReplication();
            
            Info("Started cluster manager for server {0} on cluster {1} as {2} node with session-id {3}",
                ServerName, ClusterName, SelfNode.ZkPath, zk.SessionId);
        }

        /// <summary>
        /// Creates cluster and replication Zoo Keeper paths
        /// </summary>
        private void SetupPaths()
        {
            // create missing paths
            CreateZkPath(ZkClusterPath, true);
            CreateZkPath(ZkReplicationPath, true);
        }

        /// <summary>
        /// Kills the Zoo Keeper connection
        /// </summary>
        public virtual void Stop()
        {
            StopZk();
        }

        public virtual void Dispose()
        {
            Stop();
        }
    }
}
